package org.stvd.service.quartz.impl;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import org.stvd.common.utils.StringsUtil;
import org.stvd.entities.quartz.QuartzJob;

import net.sf.json.JSONObject;

/**
 * @title QuartzHandler
 * @description 定时任务处理器
 * @author houzx
 * @date 2022年03月09日
 */
@Service
public class QuartzHandler {

    Logger log = LoggerFactory.getLogger(QuartzHandler.class);
    
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
    
    private Scheduler scheduler;

    /**
     * 新增定义任务
     * @param job   定义任务
     * @param clazz 任务执行类
     * @return 新增结果
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public boolean start(QuartzJob job, Class clazz) {
        try {
            String jobName = job.getJobName();
            String jobGroup = job.getJobGroup();
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), jobGroup);
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (null == cronTrigger) {
                // 处理参数
                Map<String, String> map = new HashMap<>(5);
                String jobDataMap = job.getJobDataMap();
                if (StringsUtil.isNotEmpty(jobDataMap)) {
                    JSONObject jsonObject = JSONObject.fromObject(jobDataMap);
                    Map parseMap = (Map) JSONObject.toBean(jsonObject, Map.class);
                    parseMap.forEach((k, v) -> map.put(String.valueOf(k), String.valueOf(v)));
                }
                // 启动定时任务
                JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobName, jobGroup)
                        .setJobData(new JobDataMap(map)).build();
                cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup)
                        .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())
                                .withMisfireHandlingInstructionDoNothing()).build();
                scheduler.scheduleJob(jobDetail, cronTrigger);
                if (!scheduler.isShutdown()) {
                    scheduler.start();
                }
            } else {
                // 重启定时任务
                cronTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())
                                .withMisfireHandlingInstructionDoNothing()).build();
                scheduler.rescheduleJob(triggerKey, cronTrigger);
            }
            return true;
        } catch (SchedulerException e) {
            log.info("启动定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 暂停定时任务
     * @param job 定时任务
     * @return 暂停结果
     */
    public boolean pause(QuartzJob job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            JobKey jobKey = trigger.getJobKey();
            scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            log.info("暂停定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 立即执行一次
     * @param job 定时任务
     * @return 执行结果
     */
    public boolean runOnce(QuartzJob job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            JobKey jobKey = trigger.getJobKey();
            scheduler = schedulerFactoryBean.getScheduler();
            scheduler.triggerJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            log.info("执行定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 更新定时任务
     * @param job 定时任务
     * @return 更新结果
     */
    public boolean update(QuartzJob job) {
        try {
            delete(job);
            start(job, Class.forName(job.getBeanClass()));
            return true;
        } catch (ClassNotFoundException e) {
            log.info("更新定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 删除定时任务
     * @param job 定时任务
     * @return 删除结果
     */
    public boolean delete(QuartzJob job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            JobKey jobKey = trigger.getJobKey();
            scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            log.info("删除定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /***
     * 判断是否存在定时任务
     * @param job 定时任务
     * @return 是否存在
     */
    public boolean has(QuartzJob job) {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            if (!scheduler.isShutdown()) {
                TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
                return scheduler.getTrigger(triggerKey) != null;
            }
            return false;
        } catch (SchedulerException e) {
            log.info("判断是否存在定时任务异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 获得定时任务状态
     * @param job 定时任务
     * @return 任务状态
     */
    public String getStatus(QuartzJob job) {
        String status = "";
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            scheduler = schedulerFactoryBean.getScheduler();
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            status = triggerState.toString();
        } catch (Exception e) {
            log.info("获得定时任务状态异常：{}", e.getMessage());
        }
        return StringsUtil.isNotEmpty(status) ? status : Trigger.TriggerState.NONE.toString();
    }

    /**
     * 启动调度器
     * @return 启动结果
     */
    public boolean startScheduler() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            scheduler.start();
            return true;
        } catch (SchedulerException e) {
            log.info("启动调度器异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 待机调度器
     * @return 待机结果
     */
    public boolean standbyScheduler() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            if (!scheduler.isShutdown()) {
                scheduler.standby();
            }
            return true;
        } catch (SchedulerException e) {
            log.info("待机调度器异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 判断调度器是否为开启状态
     * @return 是否开启
     */
    public boolean isStarted() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            return scheduler.isStarted();
        } catch (SchedulerException e) {
            log.info("判断调度器是否为开启状态异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 判断调度器是否为关闭状态
     * @return 是否关闭
     */
    public boolean isShutdown() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            return scheduler.isShutdown();
        } catch (SchedulerException e) {
            log.info("判断调度器是否为关闭状态异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 判断调度器是否为待机状态
     * @return 是否待机
     */
    public boolean isInStandbyMode() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            return scheduler.isInStandbyMode();
        } catch (SchedulerException e) {
            log.info("判断调度器是否为待机状态异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 获得下一次执行时间
     * @param cronExpression cron表达式
     * @return 下次运行时间
     */
    public Date nextExecDate(String cronExpression) {
        try {
            if (StringsUtil.isNotEmpty(cronExpression)) {
                CronExpression ce = new CronExpression(cronExpression);
                return ce.getNextValidTimeAfter(new Date());
            }
            return null;
        } catch (ParseException e) {
            log.info("获得下一次执行时间异常：{}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 删除所有任务
     */
    public void deleteAllJobs() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    scheduler.pauseJob(jobKey);
                    scheduler.deleteJob(jobKey);
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 恢复所有任务
     */
    public void resumeAllJobs() {
        try {
            scheduler = schedulerFactoryBean.getScheduler();
            scheduler.resumeAll();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
